package com.hdu.webServer.normal;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

import static com.hdu.utils.SplitUtils.split;

@Slf4j
public class Server {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(8080));
        ssc.configureBlocking(false);
        SelectionKey sscKey = ssc.register(selector, 0, null);
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            Iterator<SelectionKey> readyKeys = selector.selectedKeys().iterator();
            while (readyKeys.hasNext()) {
                SelectionKey readyKey = readyKeys.next();
                readyKeys.remove();
                if (readyKey.isAcceptable()) {
                    handleAcceptable(readyKey, selector);
                } else if (readyKey.isReadable()) {
                    handleReadable(readyKey);
                }
            }
        }
    }

    private static void handleReadable(SelectionKey key) {
        try {
            log.info("scKey happen read event : {}", key);
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ((ByteBuffer) key.attachment());
            int read = channel.read(buffer);
            if (read == -1) {
                key.cancel();
            } else {
                split(buffer);
                if (buffer.position() == buffer.limit()) {
                    // 说明没有拆分出一条完整的消息 需要扩容
                    ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2);
                    buffer.flip();
                    newBuffer.put(buffer);
                    // 替换附件
                    key.attach(newBuffer);
                }
                log.info("read data : {}", new String(buffer.array()));
            }
        } catch (Exception e) {
            log.info("scKey client down");
            key.cancel();
        }
    }

    private static void handleAcceptable(SelectionKey key, Selector selector) throws IOException {
        log.info("sscKey happen connect event : {}", key);
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        SocketChannel sc = channel.accept();
        sc.configureBlocking(false);
        ByteBuffer buffer = ByteBuffer.allocate(16);
        // 绑定 socketChannel专用 buffer
        SelectionKey scKey = sc.register(selector, 0, buffer);
        scKey.interestOps(SelectionKey.OP_READ);
    }
}
